using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace BardsTaleMapViewer {
  public class Spellbook {
    //public static string [] _functionsName = new string [] {
    //  "S00_Light","S01_DamageSingleTarget","S02_SingleArmorClassBonus","S03_TrapZap","S04_Freeze","S05_Compass","S06_DamageBonus","S07_Heal","S08_Blind","S09_Light",
    //  "S10_Levitation","S11_DamageGroup","S12_Summon","S13_Heal","S14_StatusPoisonOldEtcUnk","S15_Light","S16_DamageBonus","S17_DamageGroup","S18_Summon","S19_Levitation",
    //  "S20_Heal","S21_TeleportUnk","S22_DamageSingleTarget","S23_GroupArmorClassBonus","S24_Eye","S25_Blind","S26_DispelIllusion","S27_Summon","S28_DamageSingleTarget","S29_DamageMalus",
    //  "S30_Summon","S31_SingleArmorClassBonus","S32_Eye","S33_DamageMalus","S34_Light","S35_Summon","S36_GroupArmorClassBonus","S37_Summon","S38_DispelIllusion","S39_DamageAllGroups",
    //  "S40_Summon","S41_StatusPoisonOldEtcUnk","S42_Summon","S43_Eye","S44_MemberBonusDamageDices","S45_SingleArmorClassBonus","S46_Light","S47_Locate","S48_RepelUndead","S49_StatusPoisonOldEtcUnk",
    //  "S50_MemberBonusDamageDices","S51_Eye","S52_PartyArmorClassBonus","S53_DamageBonus","S54_GroupArmorClassBonus","S55_DamageGroup","S56_Drain","S57_DamageGroup","S58_Light","S59_AntiMagicUnk",
    //  "S60_Summon","S61_StatusPoisonOldEtcUnk","S62_PhaseDoor","S63_PartyArmorClassBonus","S64_Heal","S65_StatusPoisonOldEtcUnk","S66_Summon","S67_RepelUndead","S68_Summon","S69_RepelUndead",
    //  "S70_Summon","S71_Heal","S72_Summon","S73_StatusPoisonOldEtcUnk","S74_Possess","S75_RepelUndead","S76_Summon","S77_Heal","S78_Summon","S79_Light",
    //  "S80_Light","S81_Summon" };
    public Game _game;

    public List<string> _spellsName_SCMW;
    public List<string> _spellsName;

    public List<Spell> _spells;
    public List<string> _spellsAcronym;
    public List<int> _spellsLevel;
    public List<int> _spellsSpellPointCost;
    public List<int> _spellsBits;
    public List<int> _spellsFunction;
    public List<int> _spellsAttribute;
    //public Dictionary<int, string> _functionsName;

    public List<int> _lightTypesDungeonDrawingDepth;
    public List<int> _lightTypesMaxDuration;
    public List<int> _lightTypesSeeHidden;

    public List<int> _summonTypesMonsterTypePlus1;
    public List<int> _groupArmorClassMalusTypesValue;
    public List<int> _selfArmorClassBonusTypesValue;
    public List<int> _groupArmorClassBonusTypesValue;
    public List<int> _damageBonusTypesValue;
    public List<int> _damageMalusTypesValue;
    public List<int> _levitationTypesDuration;
    public List<int> _repelUndeadMonsterTypesPlus1;

    public enum FunctionsEnum {
      None = 0,
      Light = 0x18CC2,
      DamageSingleTarget = 0x18EB8,
      SelfBonusAC = 0x19986,
      TrapZap = 0x19A44,
      GroupMalusAC = 0x198F0,
      Compass = 0x18B2E,
      BonusDamage = 0x18A00,
      Heal = 0x18542,
      Blind = 0x19880,
      Levitation = 0x18A78,
      DamageGroup = 0x19366,
      Summon = 0x19B64,
      Status = 0x19306,
      Teleport = 0x19F70,
      GroupBonusAC = 0x199CA,
      Eye = 0x19758,
      DispelIllusion = 0x19A60,
      MalusToHit = 0x18836,
      DamageAllGroups = 0x1933C,
      MemberBonusDamageDices = 0x18AFC,
      Locate = 0x188D4,
      RepelUndead = 0x18D86,
      PartyBonusAC = 0x197DE,
      Drain = 0x18F76,
      AntiMagic = 0x19856,
      PhaseDoor = 0x1880C,
      Possess = 0x18684
    };

    public Spellbook (Game game) {
      _game = game;

      // SpellsName SCMW
      _spellsName_SCMW = Game.ReadArrayString (0x2F376, 0x2F4B2, 79, false);
      //_spellsName_SCMW = new List<string> ();
      //int address = 0x2F376;
      //for (int i = 0; i < 88; i++) {
      //  int address2 = (int) Game._dumpAtari.ReadLong (ref address);
      //  string name = Game._dumpAtari.ReadString (address2);
      //  _spellsName_SCMW.Add (name);
      //}
      //if (address != 0x2F4D6)
      //  throw new Exception ();

      // SpellsName
      _spellsName = new List<string> ();
      for (int i = 0; i < _spellsName_SCMW.Count; i++) {
        if (i < 22)
          _spellsName.Add (_spellsName_SCMW [22 + i]);
        else if (i < 44)
          _spellsName.Add (_spellsName_SCMW [i - 22]);
        else
          _spellsName.Add (_spellsName_SCMW [i]);
      }

      // SpellsAcronyms
      _spellsAcronym = new List<string> ();
      _spellsLevel = new List<int> ();
      int address = 0x2EFE4;
      int spellLevel = -1;
      for (int i = 0; ; i++) {
        int val = Game._dumpAtari.ReadByte (address);
        if (val == 0)
          break;
        else if (val >= 0xF0)
          address++;
        else if (val < 8) {
          spellLevel = val;
          address++;
        }
        else {
          string name = Game._dumpAtari.ReadString (address, 4);
          address += 4;
          _spellsAcronym.Add (name);
          _spellsLevel.Add (spellLevel);
        }
      }
      if (address != 0x2F140)
        throw new Exception ();

      // SpellsSpellPointCost
      _spellsSpellPointCost = Game.ReadArrayInt (0x2E6A8, 0x2E6F7, 79);

      // SpellBits
      _spellsBits = Game.ReadArrayInt (0x2E6F8, 0x2E761, 105);

      // SpellsFunction
      //_spellsFunction = Game.ReadArrayLong (0x2D3B0, 0x2D4F8, 79);
      _spellsFunction = Game.ReadArrayLong (0x2D3B0, 0x2D4EC, 79);
      List<int> spellsFunctionUnk = Game.ReadArrayLong (0x2D4EC, 0x2D4F8, 3);

      // SpellsAttribute
      _spellsAttribute = Game.ReadArrayInt (0x2EC84, 0x2ECED, 105);

      // FunctionsName
      //_functionsName = new Dictionary<int, string> ();
      //_functionsName.Add ((int) _functionsEnum.Light, "Light");
      //_functionsName.Add ((int) _functionsEnum.DamageSingleTarget, "DamageSingleTarget");
      //_functionsName.Add ((int) _functionsEnum.SingleArmorClassBonus, "SingleArmorClassBonus");
      //_functionsName.Add ((int) _functionsEnum.TrapZap, "TrapZap");
      //_functionsName.Add ((int) _functionsEnum.Freeze, "Freeze");
      //_functionsName.Add ((int) _functionsEnum.Compass, "Compass");
      //_functionsName.Add ((int) _functionsEnum.DamageBonus, "DamageBonus");
      //_functionsName.Add ((int) _functionsEnum.Heal, "Heal");
      //_functionsName.Add ((int) _functionsEnum.Blind, "Blind");
      //_functionsName.Add ((int) _functionsEnum.Levitation, "Levitation");
      //_functionsName.Add ((int) _functionsEnum.DamageGroup, "DamageGroup");
      //_functionsName.Add ((int) _functionsEnum.Summon, "Summon");
      //_functionsName.Add ((int) _functionsEnum.StatusPoisonOldEtcUnk, "StatusPoisonOldEtcUnk");
      //_functionsName.Add ((int) _functionsEnum.TeleportUnk, "TeleportUnk");
      //_functionsName.Add ((int) _functionsEnum.GroupArmorClassBonus, "GroupArmorClassBonus");
      //_functionsName.Add ((int) _functionsEnum.Eye, "Eye");
      //_functionsName.Add ((int) _functionsEnum.DispelIllusion, "DispelIllusion");
      //_functionsName.Add ((int) _functionsEnum.DamageMalus, "DamageMalus");
      //_functionsName.Add ((int) _functionsEnum.DamageAllGroups, "DamageAllGroups");
      //_functionsName.Add ((int) _functionsEnum.MemberBonusDamageDices, "MemberBonusDamageDices");
      //_functionsName.Add ((int) _functionsEnum.Locate, "Locate");
      //_functionsName.Add ((int) _functionsEnum.RepelUndead, "RepelUndead");
      //_functionsName.Add ((int) _functionsEnum.PartyArmorClassBonus, "PartyArmorClassBonus");
      //_functionsName.Add ((int) _functionsEnum.Drain, "Drain");
      //_functionsName.Add ((int) _functionsEnum.AntiMagicUnk, "AntiMagicUnk");
      //_functionsName.Add ((int) _functionsEnum.PhaseDoor, "PhaseDoor");
      //_functionsName.Add ((int) _functionsEnum.Possess, "Possess");

      _lightTypesDungeonDrawingDepth = Game.ReadArrayInt (0x2F34C, 0x2F358, 12);
      _lightTypesMaxDuration = Game.ReadArrayInt (0x2EDB8, 0x2EDC4, 12);
      _lightTypesSeeHidden = Game.ReadArrayInt (0x2EDC4, 0x2EDD0, 12);

      _summonTypesMonsterTypePlus1 = Game.ReadArrayInt (0x2EF9E, 0x2EFBC, 30);
      _groupArmorClassMalusTypesValue = Game.ReadArrayInt (0x2EF3A, 0x2EF3B, 1);
      _selfArmorClassBonusTypesValue = Game.ReadArrayInt (0x2EF3C, 0x2EF3F, 3);
      _groupArmorClassBonusTypesValue = Game.ReadArrayInt (0x2EF40, 0x2EF43, 3);
      _damageBonusTypesValue = Game.ReadArrayInt (0x2EEF8, 0x2EEFB, 3);
      _damageMalusTypesValue = Game.ReadArrayInt (0x2EED8, 0x2EEDA, 2);
      _levitationTypesDuration = Game.ReadArrayInt (0x2EEE6, 0x2EEE8, 2);
      _repelUndeadMonsterTypesPlus1 = Game.ReadArrayInt (0x2EF04, 0x2EF1A, 22);

      // Spells
      _spells = new List<Spell> ();
      //for (int i = 0; i < (88 - 9); i++) {
      for (int i = 0; i < 105; i++) {
        Spell spell = new Spell (i, this);
        _spells.Add (spell);
      }
    }

    public void Dump () {
      StringBuilder sb = new StringBuilder ();
      sb.AppendFormat ("{0,3}", "#");
      sb.AppendFormat ("  {0,1}", "C");
      sb.AppendFormat ("  {0,1}", "L");
      sb.AppendFormat ("  {0,-4}", "Code");
      sb.AppendFormat ("  {0,-15}", "Name");
      sb.AppendFormat ("  {0,-22}", "Function");
      sb.AppendFormat ("  {0,-2}", "SP");
      sb.AppendFormat ("  {0,-9}", "Target");
      sb.AppendFormat ("  {0,-3}", "In");
      sb.AppendFormat ("  {0,-3}", "Out");
      sb.AppendFormat ("  {0}", "Param");
      Console.WriteLine (sb.ToString ());

      foreach (Spell spell in _spells)
        //if (spell.FunctionEnum == FunctionsEnum.RepelUndead)
        spell.Dump ();
    }

    public StringBuilder DumpHtml () {
      StringBuilder sb = new StringBuilder ();
      sb.AppendLineFormat ("<table>");
      sb.AppendFormat ("<tr>");
      sb.AppendFormat ("<th class='title'>{0}</th>", "#");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Class");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Level");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Code");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Name");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Function");
      sb.AppendFormat ("<th class='title'>{0}</th>", "SP");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Target");
      sb.AppendFormat ("<th class='title'>{0}</th>", "In Combat");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Out of Combat");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Param");
      sb.AppendFormat ("</tr>");
      sb.AppendLine ();

      foreach (Spell spell in _spells)
        //if (spell.FunctionEnum == FunctionsEnum.RepelUndead)
        sb.AppendLine (spell.DumpHtml ().ToString ());

      sb.AppendLineFormat ("</table>");
      return (sb);
    }
  }
}
